package cn.amebius.simpledocker.websocket;

import cn.amebius.simpledocker.config.DockerFactory;
import cn.amebius.simpledocker.entity.model.ContainerStatsModel;
import cn.amebius.simpledocker.entity.model.DockerClientModel;
import cn.amebius.simpledocker.entity.model.NetworkIOModel;
import cn.amebius.simpledocker.exception.DockerErrorException;
import com.alibaba.fastjson.JSON;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.async.ResultCallback;
import com.github.dockerjava.api.model.*;
import com.github.dockerjava.core.command.LogContainerResultCallback;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import javax.annotation.PostConstruct;
import java.io.Closeable;
import java.io.IOException;
import java.text.NumberFormat;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 阿伟
 * @date 2023/9/4 19:04
 */
@Slf4j
public class ContainerStatsWebSocketHandler extends BaseAbstractWebsocket {

    public ContainerStatsWebSocketHandler(String name) {
        super(name);
    }


    // 连接建立时触发
    @Override
    public void afterConnectionEstablished(WebSocketSession session){
        //https://docs.docker.com/engine/api/v1.42/#tag/Container/operation/ContainerExport
        initConnections(session);
        String containerId = (String) session.getAttributes().get("containerId");
        DockerClient dc = getDockerClient(session);
        try {
            dc.statsCmd(containerId).exec(new ResultCallback<Statistics>() {
                @Override
                public void onStart(Closeable closeable) {

                }
                @Override
                public void onNext(Statistics statistics) {
                    ContainerStatsModel containerStatsModel = null;
                    try {
                        containerStatsModel = ContainerStatsWebSocketHandler.getStats(statistics);
                        session.sendMessage(new TextMessage(JSON.toJSONString(containerStatsModel)));
                    } catch (Exception e) {
                        throw new DockerErrorException("Docker异常：查询容器状态错误！");
                    }
                }
                @Override
                public void onError(Throwable throwable) {

                }
                @Override
                public void onComplete() {

                }
                @Override
                public void close() throws IOException {
                }
            });
        } catch (Exception e) {
            throw new DockerErrorException("Docker异常：查询容器状态错误！");
        }
        destory(session);
    }

    // 连接关闭时触发
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status){
        destory(session);
    }

    public static ContainerStatsModel getStats(Statistics statistics) throws InterruptedException {
        Thread.sleep(5000);
        ContainerStatsModel retModel = new ContainerStatsModel();
        LocalTime currentTime = LocalTime.now();
        int hour = currentTime.getHour();
        int minute = currentTime.getMinute();
        int second = currentTime.getSecond();
        retModel.setCreateTime(hour + ":" + minute + ":" + second);
        //memory状态
        MemoryStatsConfig ms = statistics.getMemoryStats();
        StatsConfig stats = ms.getStats();
        long usedMemory = ms.getUsage() - stats.getCache();
        Long availableMemory = ms.getLimit();
        retModel.setUsedMemory(usedMemory);
        retModel.setAvailableMemory(availableMemory);
        double memoryUsage = ((double) usedMemory / availableMemory);
        retModel.setMemoryUsage(String.valueOf(memoryUsage * 100.0));
        //cpu状态
        CpuStatsConfig cs = statistics.getCpuStats();
        CpuStatsConfig ps = statistics.getPreCpuStats();
        Long numberCpus = cs.getOnlineCpus();
        long cpuDelta = cs.getCpuUsage().getTotalUsage() - ps.getCpuUsage().getTotalUsage();
        Long psSystemCpuUsage = ps.getSystemCpuUsage();
        Long csSystemCpuUsage = cs.getSystemCpuUsage();
        if (psSystemCpuUsage == null) {
            psSystemCpuUsage = csSystemCpuUsage;
        }
        long systemCpuDelta = csSystemCpuUsage - psSystemCpuUsage;
        retModel.setCpuUsage(String.valueOf(((double) cpuDelta / systemCpuDelta) * numberCpus * 100.0));
        //网络状态
        Map<String, StatisticNetworksConfig> networks = statistics.getNetworks();
        Set<String> keys = networks.keySet();
        ArrayList<NetworkIOModel> ioModels = new ArrayList<>();
        for (String key : keys) {
            NetworkIOModel ioModel = new NetworkIOModel();
            ioModel.setEthName(key);
            StatisticNetworksConfig nc = networks.get(key);
            Long txBytes = nc.getTxBytes();
            Long rxBytes = nc.getRxBytes();
            ioModel.setKiloByte((txBytes + rxBytes) / 1024 );
            Long rxPackets = nc.getRxPackets();
            Long txPackets = nc.getTxPackets();
            ioModel.setPackets(rxPackets + txPackets);
            ioModels.add(ioModel);
        }
        retModel.setNetworkUsage(ioModels);
        return retModel;
    }
}
